package xworker.lang.actions.code;

import org.xmeta.ActionContext;
import org.xmeta.Thing;
import org.xmeta.cache.ThingEntry;

public class FakeGroovyAction {
    private static final Object lockObj = new Object();
    ThingEntry parentEntry;
    String attributeName;
    Thing groovyAction;

    public FakeGroovyAction(Thing parent, String attributeName){
        this.attributeName = attributeName;
        parentEntry = new ThingEntry(parent);

        groovyAction = new Thing("xworker.groovy.GroovyAction");
        groovyAction.set("name", attributeName);
        groovyAction.getMetadata().setPath(parent.getMetadata().getPath() + "/@fakeGroovy" + attributeName);
        groovyAction.set("code", parent.getString(attributeName));
        groovyAction.setParent(parent);

    }

    public Object execute(ActionContext actionContext){
        if(parentEntry.isChanged()){
            groovyAction.set("code", parentEntry.getThing().getString(attributeName));
        }

        return groovyAction.getAction().run(actionContext);
    }

    public Thing getThing(){
        return parentEntry.getThing();
    }

    public String getAttributeName() {
        return attributeName;
    }

    public Thing getGroovyAction() {
        return groovyAction;
    }

    public static FakeGroovyAction getInstance(Thing thing, String attributeName){
        if(thing == null){
            return null;
        }

        synchronized (lockObj) {
            String key = "_facke_groovy_" + attributeName;
            FakeGroovyAction fakeGroovyAction = thing.getData(key);
            if (fakeGroovyAction == null) {
                fakeGroovyAction = new FakeGroovyAction(thing, attributeName);
                thing.setData(key, fakeGroovyAction);
            }

            return fakeGroovyAction;
        }
    }

    /**
     * 把模型的指定属性作为Groovy脚本执行，其中会生成FakeGroovyAction并缓存到模型上。
     */
    public static Object executeThingAttribute(Thing thing, String attributeName, ActionContext actionContext){
        return getInstance(thing, attributeName).execute(actionContext);
    }
}
